home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
-
- use strict;
- use warnings;
-
-
- my $RULES = "/etc/udev/rules.d/70-persistent-net.rules";
-
-
- #-----------------------------------------------------------------------------#
- # Sanity check
- #-----------------------------------------------------------------------------#
- die "$RULES does not exist to fix\n" unless -f $RULES;
-
-
- #-----------------------------------------------------------------------------#
- # Parse existing /etc/udev/rules.d/70-persistent-net.rules
- #-----------------------------------------------------------------------------#
-
- open RULES, $RULES
- or die "Unable to open $RULES: $!";
-
- my @rules;
- while (<RULES>) {
- # Rules may cross multiple lines when lines ends in \
- while (/\\$/ && (my $extra = <RULES>)) {
- $_ .= $extra;
- }
-
- # Skip lines that are empty, have only whitespace and/or comments
- if (/^\s*(\#.*)?$/) {
- push @rules, [ $_ ];
- next;
- }
-
- # Parse rule elements
- my $rule = [];
- while (/(?:([\s,]*)((\S*?)\s*(==|\+=|!=|:=|=)\s*\"([^\"]*)\")|(.+))/gs) {
- if (defined $1) {
- push @{$rule}, $1 if length $1;
- push @{$rule}, {
- 'text' => $2,
- 'key' => $3,
- 'op' => $4,
- 'val' => $5
- };
- } else {
- push @{$rule}, $6;
- }
- }
-
- push @rules, $rule;
- }
-
- close RULES
- or warn "Error while closing $RULES: $!";
-
-
- #-----------------------------------------------------------------------------#
- # Fix rule entries
- #-----------------------------------------------------------------------------#
-
- RULE: foreach my $rule (@rules) {
- my $has_rule = 0;
- my $has_match = 0;
- my $has_type = 0;
- my $name_idx = -1;
- my $name;
- my $address;
-
- MATCH: foreach my $idx (0..$#{$rule}) {
- my $match = $rule->[$idx];
- next unless ref $match;
- $has_rule = 1;
-
- if ($match->{key} =~ /^ATTRS?{type}$/) {
- # Rule matches on interface type
- $has_type = 1;
- } elsif ($match->{key} =~ /^ATTRS?{address}$/) {
- # Rule matches on MAC address
- $has_match = 1;
- $address = $match->{val};
- } elsif ($match->{key} =~ /^ATTRS?{[^}]*}|ENV{[^}]*}|KERNELS$/) {
- # Rule matches on a possibly unique attribute
- $has_match = 1;
- } elsif ($match->{key} =~ /^NAME$/ && $match->{op} =~ /^:?=$/) {
- # Name setting
- $name_idx = $idx;
- $name = $match->{val};
- }
- }
-
- next unless $has_rule;
-
- # Comment out lines that don't match a device by any potentially unique
- # property, since they'll match everything
- unless ($has_match) {
- unshift @{$rule}, "#removed by upgrade, will match any device\n# ";
- $name_idx++;
- }
-
- # Add a match on type for any rule missing that to avoid matching
- # "master" devices
- unless ($has_type) {
- my $type;
-
- # Make sure that the device currently has the "1" (Ethernet) type
- if (-f "/sys/class/net/$name/type"
- && `cat /sys/class/net/$name/type` =~ /^1\s*$/) {
- # It does
- $type = "1";
- } elsif (defined $address) {
- # It doesn't, it's possible that we've already renamed it to
- # something else and a device exists with the right MAC address
- # and a different name
- opendir NET, "/sys/class/net"
- or die "Unable to open /sys/class/net: $!";
-
- my $found = 0;
- while (my $dev = readdir(NET)) {
- next if $dev =~ /^\./;
- next unless (-f "/sys/class/net/$dev/address"
- && `cat /sys/class/net/$dev/address` =~ /^$address\s*$/i);
- $found = 1;
-
- next unless (-f "/sys/class/net/$dev/type"
- && `cat /sys/class/net/$dev/type` =~ /^1\s*$/);
-
- # Found a device with a matching address and the right type
- $type = "1";
- }
-
- closedir NET
- or die "Error while closing /sys/class/net: $!";
-
- # No device with the matching MAC address found (unplugged?)
- # stick type in anyway
- $type = "1" unless $found;
- }
-
- # Append a rule to match the type. If we couldn't find an Ethernet
- # device with the set name, or a different name but the right address,
- # then we don't attempt to change the file and instead leave a comment
- # to highlight a line that might be a problem.
- if (defined $type) {
- my $match = {
- 'text' => "ATTR{type}==\"$type\"",
- 'key' => 'ATTR{type}',
- 'op' => '==',
- 'val' => "$type"
- };
- splice(@{$rule}, $name_idx, 0, $match, ", ");
- $name_idx += 2;
- } elsif ($has_match) {
- unshift @{$rule}, "#following line may cause a device to become stuck as ${name}_rename\n#add ADDR{type}==\"...\" if that happens\n";
- $name_idx++;
- }
- }
- }
-
-
- #-----------------------------------------------------------------------------#
- # Write new /etc/udev/rules.d/70-persistent-net.rules
- #-----------------------------------------------------------------------------#
-
- open RULES, ">$RULES.new"
- or die "Unable to open $RULES.new: $!";
-
- foreach my $rule (@rules) {
- my $line = "";
- foreach my $match (@{$rule}) {
- if (ref $match) {
- $line .= $match->{text};
- } else {
- $line .= $match;
- }
- }
-
- print RULES $line;
- }
-
- close RULES
- or warn "Error while closing $RULES: $!";
- rename "$RULES.new", $RULES
- or die "Unable to replace $RULES: $!";
-